package com.stevejrong.waiter.aa.component.infrastructure.util;

import java.io.IOException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.interfaces.RSAPublicKey;

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import com.nimbusds.jose.jwk.RSAKey;
import com.stevejrong.waiter.aa.component.infrastructure.RSAConfig;

/**
 * 工具类 - RSA加解密工具类
 */
public final class RSAUtil {
	private volatile static KeyPair keyPair = null;

	/**
	 * 从RSA证书文件中，获取到RSA的公钥和私钥对象
	 * <p>
	 * 使用了双重检查加锁的方式，保证KeyPair实例获取的线程安全。
	 *
	 * @param resourceLoader Spring的资源加载器。用于从classpath下读取jks格式的证书文件。
	 * @param rsaConfig      RSA系统配置类。用于读取RSA文件的相关配置。
	 * @return 同时含RSA的公钥和私钥的对象
	 */
	private static KeyPair getKetPairFromJksFile(ResourceLoader resourceLoader, RSAConfig rsaConfig) {
		if (keyPair == null) {
			synchronized (RSAUtil.class) {
				if (keyPair == null) {
					Resource rsaKeyResource = resourceLoader.getResource(rsaConfig.getJksFilePath());

					try {
						KeyStore keyStore = KeyStore.getInstance("JKS");
						keyStore.load(rsaKeyResource.getInputStream(), rsaConfig.getPasswordCharArray());
						Key key = keyStore.getKey(rsaConfig.getAliasName(), rsaConfig.getPasswordCharArray());

						if (key instanceof PrivateKey) {
							keyPair = new KeyPair(keyStore.getCertificate(rsaConfig.getAliasName()).getPublicKey(),
									(PrivateKey) key);
						}
					} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException
							| UnrecoverableKeyException e) {
						throw new RuntimeException(e);
					}
				}
			}
		}

		return keyPair;
	}

	/**
	 * 从RSA证书文件中，获取到RSA的私钥对象
	 *
	 * @param resourceLoader Spring的资源加载器。用于从classpath下读取jks格式的证书文件。
	 * @param rsaConfig      RSA系统配置类。用于读取RSA文件的相关配置。
	 * @return 含RSA私钥的对象
	 */
	public static PrivateKey getPrivateKey(ResourceLoader resourceLoader, RSAConfig rsaConfig) {
		return getKetPairFromJksFile(resourceLoader, rsaConfig).getPrivate(); // 获取并返回私钥
	}

	/**
	 * @param resourceLoader Spring的资源加载器。用于从classpath下读取jks格式的证书文件。
	 * @param rsaConfig      RSA系统配置类。用于读取RSA文件的相关配置。
	 * @return 含RSA公钥的对象
	 */
	public static PublicKey getPublicKey(ResourceLoader resourceLoader, RSAConfig rsaConfig) {
		return getKetPairFromJksFile(resourceLoader, rsaConfig).getPublic(); // 获取并返回公钥
	}

	public static RSAKey getRSAKey(PublicKey publicKey, PrivateKey privateKey) {
		return new RSAKey.Builder((RSAPublicKey) publicKey).privateKey(privateKey).build(); // 构建同时携带公私钥的RSAKey对象并返回
	}
}
